#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>


#include "public.h"
#include "list.h"
#include "io.h"
#include "NetEngine.h"
#include "prober_dev.h"

static void prober_dev_commu_deal(struct _NET_SOCKET_T *pf)
{
	printf("recv the data\n");
	stProber_dev.buff = Malloc(pf->data_len);
	memcpy(stProber_dev.buff, pf->buf, pf->data_len);
	stProber_dev.stat = PROBER_DEV_STAT_READY;
	Sem_post(&stProber_dev.prober_sem);
	return ;
}

static void prober_dev_info_updata()
{
	PS_PARK_PROBER_HEAD pstPacketHead;
	stProber_dev.cur_buff = stProber_dev.buff;
	pstPacketHead = (PS_PARK_PROBER_HEAD)stProber_dev.cur_buff;
	stProber_dev.cur_config_id = pstPacketHead->config_id;
	stProber_dev.prober_id = pstPacketHead->probr_id;
	strncpy(stProber_dev.agent_addr, pstPacketHead->agent_addr, 20);
	stProber_dev.sensor_num = pstPacketHead->sensor_num;
	stProber_dev.pstSensor_a = (PS_SENSOR)pstPacketHead->sensor;
	return ;
}
	

static int prober_dev_commu_init()
{
	int ret;
	ret = net_init(&stProber_dev.stNet);
	if (ret != 0)
	{
		ERR_SYS("net_init error!");
	}

	stProber_dev.listen_fd.s_type = NET_ST_SERVER;
	stProber_dev.listen_fd.in_event = prober_dev_commu_deal;
	ret = net_socket_init(&stProber_dev.stNet, &stProber_dev.listen_fd, NULL, PARK_PROBER_SEARCH_PORT);
	if (ret != 0)
	{
		ERR_SYS("net_socket_init error!");
	}
	return 0;
}

int prober_dev_get_agent_addr(char *ip_addr)
{
	strncpy(ip_addr, "192.168.12.101", 20);
	return 0;
}

static int prober_dev_commu_send_packet(const char *buff, int len)
{
	int ret;
	bzero(&stProber_dev.connect_fd, sizeof(NET_SOCKET_T));
	stProber_dev.connect_fd.s_type = NET_ST_CLIENT;
	stProber_dev.connect_fd.in_event = NULL;
	ret = net_socket_init(&stProber_dev.stNet, &stProber_dev.connect_fd, stProber_dev.agent_addr, PARK_PROBER_LISTEN_PORT);
	if (ret != 0)
		return ret;
	ret = net_socket_send_data(&stProber_dev.connect_fd, buff, len);
	net_socket_destroy(&stProber_dev.connect_fd);
	return ret;
}

int prober_dev_commu_send_req()
{
	int ret;
	S_SENSOR_TRAP_HEAD stTrapPacket;
	bzero(&stTrapPacket, sizeof(S_SENSOR_TRAP_HEAD));
	stTrapPacket.trap_type = SENSOR_TRAP_TYPE_REQ;
	SOCKET_GetLocalIp("eth0", stTrapPacket.prober_addr);
	ret = prober_dev_commu_send_packet((const char*)&stTrapPacket, sizeof(S_SENSOR_TRAP_HEAD));
	return ret;
}

int prober_dev_read(io_info_t* pio, struct probe_ackpkt_t* pAckpkt)
{
	int i = 0;
	char szTemp[20] = {0};
	for (i = 0; i < 7;)
	{
		if(io_recv(pio, szTemp+i, 1) != 1){
			DBG("recv data error.\n");
			return -1;
		}
		//printf("recv data: 0x%02x \n",szTemp[i]);
		if(i == 0 && szTemp[0] != 0xAA)
			continue;
		if(i == 1 && szTemp[1] != 0xBB){
			if(szTemp[1] == 0xAA) continue;
			i = 0;
			continue;
		}
		i++;
	}
	DBG("recv data: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x \n",szTemp[0],szTemp[1],szTemp[2],szTemp[3],szTemp[4],szTemp[5],szTemp[6]);
	if(szTemp[3] != 0xDD || szTemp[6] != 0xCC){
		return -1;
	}
	
	pAckpkt->head[0] = szTemp[0];
	pAckpkt->head[1] = szTemp[1];
	pAckpkt->address = szTemp[2];
	pAckpkt->cmd = szTemp[3];
	pAckpkt->distance = (unsigned short)(szTemp[4]<<8|szTemp[5]);;
	pAckpkt->tail = szTemp[6];
	return 0;
}

#define add_sensor_list_init() \
	do {\
		stProber_dev.trap_num = 0;\
		}while(0)

#define add_sensor_list(id, stat) \
	do {\
			if (stProber_dev.trap_num<PARK_PROBER_MAX_SENSOR) {\
				stProber_dev.stSensor_trap_a[stProber_dev.trap_num].sensor_id = id;\
				stProber_dev.stSensor_trap_a[stProber_dev.trap_num].sensor_stat = stat;\
				stProber_dev.trap_num++; }\
		}while(0)


static void prober_dev_sensor_poll(PS_SENSOR pstSensor)
{
	struct probe_cmdpkt_t cmdpkt;
	struct probe_ackpkt_t ackpkt;
	int max_value;

	if (pstSensor->io_addr<0 || pstSensor->io_addr>PROBER_IO_NUM)
	{
		DBG("sensor id (%d) io addr error %d.\n", pstSensor->sensor_id, pstSensor->io_addr);
		pstSensor->stat = SENSOR_STAT_ERROR;
		return;
	}

	DBG("prober the sensor io_addr(%d) host_addr(%d)\n", pstSensor->io_addr, pstSensor->host_addr);
	
	io_select(stProber_dev.pio, pstSensor->io_addr+1);				
	memset(&cmdpkt, 0, sizeof(cmdpkt));
	cmdpkt.head[0] = 0xAA;
	cmdpkt.head[1] = 0xBB;
	cmdpkt.tail = 0xCC;
	cmdpkt.address = (char)pstSensor->host_addr;
	cmdpkt.cmd = 0xC4;
	io_send(stProber_dev.pio, (char*)&cmdpkt, sizeof(cmdpkt));
	//usleep(15000); // 100000 modify by lvrain 2013.07.11

	max_value = pstSensor->high+pstSensor->high/2;
	
	memset(&ackpkt, 0, sizeof(ackpkt));
	if(prober_dev_read(stProber_dev.pio, &ackpkt) != 0)
	{
		pstSensor->stat = SENSOR_STAT_OFFLINE;
	}
	else
	{
		if (ackpkt.distance > max_value)
		{
			pstSensor->stat = SENSOR_STAT_ERROR;
		}
		else if (pstSensor->high - ackpkt.distance > SENSOR_WHETHER_HAVE_CAR)
		{
			pstSensor->stat = SENSOR_STAT_HAVECAR;
		}
		else
		{
			pstSensor->stat = SENSOR_STAT_NOCAR;
		}
	}

	if (pstSensor->stat != pstSensor->old_stat)
	{
		add_sensor_list(pstSensor->sensor_id, pstSensor->stat);
		pstSensor->old_stat = pstSensor->stat;
	}

	return;
}

static void prober_dev_sensor_poll_first(PS_SENSOR pstSensor)
{
	struct probe_cmdpkt_t cmdpkt;
	struct probe_ackpkt_t ackpkt;
	int max_value;
	if (pstSensor->io_addr<0 || pstSensor->io_addr>PROBER_IO_NUM)
	{
		DBG("sensor id (%d) io addr error %d.\n", pstSensor->sensor_id, pstSensor->io_addr);
		pstSensor->stat = SENSOR_STAT_ERROR;
		return;
	}

	DBG("prober the sensor io_addr(%d) host_addr(%d)\n", pstSensor->io_addr, pstSensor->host_addr);
	io_select(stProber_dev.pio, pstSensor->io_addr+1);					
	memset(&cmdpkt, 0, sizeof(cmdpkt));
	cmdpkt.head[0] = 0xAA;
	cmdpkt.head[1] = 0xBB;
	cmdpkt.tail = 0xCC;
	cmdpkt.address = (char)pstSensor->host_addr;
	cmdpkt.cmd = 0xC4;
	io_send(stProber_dev.pio, (char*)&cmdpkt, sizeof(cmdpkt));
	usleep(15000); // 100000 modify by lvrain 2013.07.11
	
	max_value = pstSensor->high+pstSensor->high/2;
		
	memset(&ackpkt, 0, sizeof(ackpkt));
	if(prober_dev_read(stProber_dev.pio, &ackpkt) != 0)
	{
		pstSensor->stat = SENSOR_STAT_OFFLINE;
	}
	else
	{
		if (ackpkt.distance > max_value)
		{
			pstSensor->stat = SENSOR_STAT_ERROR;
		}
		else if (pstSensor->high - ackpkt.distance > SENSOR_WHETHER_HAVE_CAR)
		{
			pstSensor->stat = SENSOR_STAT_HAVECAR;
		}
		else
		{
			pstSensor->stat = SENSOR_STAT_NOCAR;
		}
	}
	

	add_sensor_list(pstSensor->sensor_id, pstSensor->stat);
	pstSensor->old_stat = pstSensor->stat;
		
	
	return;
}


static int prober_dev_commu_send_trap(int trap_type)
{
	int buff_len;
	int ret;
	char *buff;
	PS_SENSOR_TRAP_HEAD pstTrap;
	
	buff_len = sizeof(S_SENSOR_TRAP_HEAD) + stProber_dev.trap_num*sizeof(S_SENSOR_TRAP);
	buff = Malloc(buff_len);
	pstTrap = (PS_SENSOR_TRAP_HEAD)buff;

	pstTrap->config_id = stProber_dev.cur_config_id;
	pstTrap->prober_id = stProber_dev.prober_id;
	pstTrap->trap_type = trap_type;
	pstTrap->sensor_num = stProber_dev.trap_num;
	memcpy(pstTrap->sensor, stProber_dev.stSensor_trap_a, stProber_dev.trap_num*sizeof(S_SENSOR_TRAP));
	ret = prober_dev_commu_send_packet(buff, buff_len);
	free(buff);
	return ret;
}

void *prober_dev_do_poll(void *arg)
{
	int i;
	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
	while(1)
	{
		add_sensor_list_init();
		for (i=0; i<stProber_dev.sensor_num; i++)
		{
			prober_dev_sensor_poll(&stProber_dev.pstSensor_a[i]);
		}

		if (stProber_dev.trap_num != 0)
		{
			prober_dev_commu_send_trap(SENSOR_TRAP_TYPE_STATCHANGE);
		}
		pthread_testcancel();
		sleep(1);
		pthread_testcancel();
	}
}

void prober_dev_do_poll_first()
{
	int i;
	add_sensor_list_init();
	for (i=0; i<stProber_dev.sensor_num; i++)
	{
		prober_dev_sensor_poll_first(&stProber_dev.pstSensor_a[i]);
	}

	prober_dev_commu_send_trap(SENSOR_TRAP_TYPE_DATAREQ);
	return;
}



void *prober_dev_stat(void *arg)
{
	struct timespec ts;
	int ret;
	sleep(3);
	stProber_dev.stat = PROBER_DEV_STAT_INIT;
	while(1)
	{
		switch (stProber_dev.stat)
		{
			case PROBER_DEV_STAT_INIT:
				bzero(&stProber_dev, sizeof(S_PROBER_DEV));
				stProber_dev.pio = io_open();
				Sem_init(&stProber_dev.prober_sem, 0, 0);				 
				prober_dev_get_agent_addr(stProber_dev.agent_addr);
				prober_dev_commu_init();
				stProber_dev.stat = PROBER_DEV_STAT_WAIT;
				break;
				
			case PROBER_DEV_STAT_WAIT:
				prober_dev_commu_send_req();
				stProber_dev.oldstat = stProber_dev.stat;
				stProber_dev.stat = PROBER_DEV_STAT_IDLE;
				break;

			case PROBER_DEV_STAT_CREAT:
				prober_dev_info_updata();
				prober_dev_do_poll_first();
				Pthread_create(&stProber_dev.pid, NULL, prober_dev_do_poll, NULL);
				stProber_dev.stat = PROBER_DEV_STAT_RUN;
				break;
				
			case PROBER_DEV_STAT_READY:
				ret = pthread_kill(stProber_dev.pid, 0);
				if (ret==0) //pthread exist
				{
					pthread_cancel(stProber_dev.pid);
					pthread_join(stProber_dev.pid, NULL);
				}
				
				if (stProber_dev.cur_buff != NULL)
				{
					free(stProber_dev.cur_buff);
					stProber_dev.cur_buff = NULL;
				}
				stProber_dev.stat = PROBER_DEV_STAT_CREAT;
				break;
				
			case PROBER_DEV_STAT_RUN:
				stProber_dev.oldstat = stProber_dev.stat;
				stProber_dev.stat = PROBER_DEV_STAT_IDLE;
				break;
				
			case PROBER_DEV_STAT_IDLE:
				//printf("stat idle\n");
				ts.tv_sec = time(NULL)+PROBER_STAT_IDLE_TIMEOUT;
				ts.tv_nsec = 0;
				while((ret=sem_timedwait(&stProber_dev.prober_sem, &ts))==-1 && errno==EINTR)
					continue;
				if (ret == -1)
				{
					if (errno == ETIMEDOUT)
					{
						stProber_dev.stat = stProber_dev.oldstat;
					}
					else
					{
						ERR_SYS("sem_timedwait error");
					}
				}
				break;
		}
	}
}

int main(void)
{
	prober_dev_stat(NULL);
	return 0;
}
